module VGA_Controller(reset,
							clk,							
							VGA_CLK,
							VGA_HS,
							VGA_VS,
							VGA_BLANK,
							VGA_SYNC,
							VGA_R,
							VGA_G,
							VGA_B,
							VGA_ADDR,
							VGA_DATA,
							VGA_WHICH_BYTE
							);
							
input reset;
input clk;

output VGA_CLK;
output VGA_HS;
output VGA_VS;
output VGA_BLANK;
output VGA_SYNC;
output reg [9:0] VGA_R;
output reg [9:0] VGA_G;
output reg [9:0] VGA_B;
output [17:0] VGA_ADDR;
output VGA_WHICH_BYTE;
input [7:0] VGA_DATA;

							
parameter HTOTAL = 800;
parameter HSYNC = 96;
parameter HBACK_PORCH = 48;
parameter HACTIVE = 640;
parameter HFRONT_PORCH = 16;

parameter VTOTAL = 525;
parameter VSYNC = 2;
parameter VBACK_PORCH = 33;
parameter VACTIVE = 480;
parameter VFRONT_PORCH = 10;

reg [17:0] VGA_ADDR = 0;

reg [9:0] HCount = 0;
reg [9:0] VCount = 0;
wire EndOfLine;
wire EndOfField;

reg vga_hblank = 1;
reg vga_hsync = 1;
reg vga_vblank = 1;
reg vga_vsync = 1;

reg [1:0] vga_red;
reg [1:0] vga_blue;
reg [1:0] vga_green;

reg VGA_WHICH_BYTE = 0;
reg DUPLICATE_PIXEL = 0;
integer i = 0;
integer j = 0;


//HCOUNTER
always @(posedge clk or negedge reset) begin
	if(reset == 0) begin
		HCount <= 0;
	end else begin
		if (EndOfLine == 1) begin
			HCount <= 0;
		end else begin
			HCount <= HCount + 1;
		end
	end
end

assign EndOfLine = (HCount == HTOTAL - 1)? 1: 0;

//VCOUNTER
always @(posedge clk or negedge reset) begin
	if(reset == 0) begin
		VCount <= 0;
	end else begin
		if(EndOfLine == 1) begin
			if (EndOfField == 1) begin
				VCount <= 0;
			end else begin
				VCount <= VCount + 1;
			end
		end
	end
end

assign EndOfField = (VCount == VTOTAL - 1)? 1: 0;

//HSYNCGEN
always @(posedge clk or negedge reset) begin
	if(reset == 0) begin
		vga_hsync <= 1;
	end else begin
		if (EndOfLine == 1) begin
			vga_hsync <= 1;
		end else if(HCount == HSYNC - 1) begin
			vga_hsync <= 0;
		end
	end
end

//HBLANKCGEN
always @(posedge clk or negedge reset) begin
	if(reset == 0) begin
		vga_hblank <= 1;
	end else begin
		if (HCount == HSYNC + HBACK_PORCH - 1) begin
			vga_hblank <= 0;
		end else if(HCount == HSYNC + HBACK_PORCH + HACTIVE - 1) begin
			vga_hblank <= 1;
		end
	end
end

//VSYNCGEN
always @(posedge clk or negedge reset) begin
	if(reset == 0) begin
		vga_vsync <= 1;
	end else begin
		if (EndOfLine == 1) begin
			if(EndOfField == 1) begin
				vga_vsync <= 1;
			end else if(VCount == VSYNC - 1) begin
				vga_vsync <= 0;
			end
		end
	end
end

//VBLANKCGEN
always @(posedge clk or negedge reset) begin
	if(reset == 0) begin
		vga_vblank <= 1;
	end else begin
		if(EndOfLine == 1) begin
			if (VCount == VSYNC + VBACK_PORCH - 1) begin
				vga_vblank <= 0;
			end else if(VCount == VSYNC + VBACK_PORCH + VACTIVE - 1) begin
				vga_vblank <= 1;
			end
		end
	end
end

//VideoOut
always @(posedge clk or negedge reset) begin
	if(reset == 0) begin
		VGA_R <= 10'b0000000000;
		VGA_G <= 10'b0000000000;
		VGA_B <= 10'b0000000000;
		VGA_ADDR <= 0;
end else begin				
		if ((VGA_DATA !== 8'bx) && (vga_hblank == 0 && vga_vblank == 0)) begin		
			vga_red = (VGA_DATA & 8'hC0) >> 6;
			vga_green = (VGA_DATA & 8'h30) >> 4;
			vga_blue = (VGA_DATA & 8'hC) >> 2;
		
			VGA_R = {5{vga_red}};
			VGA_G = {5{vga_green}};
			VGA_B = {5{vga_blue}};
			
			j = j + 1;
			if (j >= 640) begin
				j = 0;
				i = i + 1;
			end
			if (i >= 480) begin
				i = 0;
			end
			
			VGA_ADDR = ((320*(i/2) + (j/2))/2)+17'h36a00; //M[D][C] = C*i + j
			
			if (!(j%2)) begin
				VGA_WHICH_BYTE = ~VGA_WHICH_BYTE;
			end
			
			
			/*
			if (DUPLICATE_PIXEL) begin
				if (VGA_WHICH_BYTE) begin
					VGA_ADDR <= VGA_ADDR +1;
				end
				if (VGA_ADDR >= 38400) begin
					VGA_ADDR <= 0;
				end
				VGA_WHICH_BYTE <= ~VGA_WHICH_BYTE;			
			end
			DUPLICATE_PIXEL <= ~DUPLICATE_PIXEL;
			*/
		end else begin
			VGA_R <= 10'b0000000000;
			VGA_G <= 10'b0000000000;
			VGA_B <= 10'b0000000000;
		end
	end
end

assign VGA_CLK = clk;
assign VGA_HS = ~vga_hsync;
assign VGA_VS = ~vga_vsync;
assign VGA_SYNC = 0;
assign VGA_BLANK = ~(vga_hsync | vga_vsync);

endmodule
